package com.qd.panda.space;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.page.PageUtil;
import com.cdqidi.valid.group.DefaultGroup;
import com.qd.common.panda.domain.entity.space.CarOwnerParkSpaceDTO;
import com.qd.common.panda.domain.entity.space.OwnParkSpaceTenantDTO;
import com.qd.common.panda.domain.entity.space.ParkSpaceTenantDTO;
import com.qd.common.panda.domain.entity.stroke.PayParamDTO;
import com.qd.panda.service.space.ParkSpaceHolderService;
import com.qd.panda.service.space.ParkSpaceService;
import com.qd.panda.service.space.ParkSpaceTenantService;
import com.qd.panda.service.stroke.UserStrokeHolderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 短期租赁/APP_车主端车位租赁信息
 *
 * @author sjk
 */
@RequiredArgsConstructor
@Validated
@RestController
@RequestMapping("/app/carOwnParkSpace/")
@Slf4j
public class CarOwnParkSpaceController {
    private final ParkSpaceService parkSpaceService;
    private final ParkSpaceHolderService parkSpaceHolderService;
    private final ParkSpaceTenantService parkSpaceTenantService;
    private final RedissonClient redissonClient;

    /**
     * 列表
     *
     * @param dto 查询参数以及页数和每页显示条数
     * @return 列表信息
     */
    @GetMapping(value = "/page")
    public IPage<CarOwnerParkSpaceDTO> page(CarOwnerParkSpaceDTO dto) {
        dto = Optional.ofNullable(dto).orElse(new CarOwnerParkSpaceDTO());
        dto.setEnd(ConstantDto.SF0);
        return parkSpaceService.carOwnerPage(PageUtil.buildPage(dto), dto);
    }

    /**
     * 详情
     *
     * @return 列表信息
     */
    @GetMapping(value = "/getById")
    public CarOwnerParkSpaceDTO getById(@Validated @NotBlank(message = "ID不能为空") String id) {
        return parkSpaceService.getByCarOwnerParkSpace(id);
    }

    /**
     * 计算价格
     *
     * @param dto 页面对象
     * @return 页面对象
     */
    @GetMapping(value = "/calculatePrice")
    public ApiResultWrapper<Object> calculatePrice(ParkSpaceTenantDTO dto) {
        if (!StringUtils.hasLength(dto.getSid())) {
            return ApiResult.error("租赁ID不能为空");
        }
        if (!StringUtils.hasLength(dto.getStartDate())) {
            return ApiResult.error("租赁开始时间不能为空");
        }
        if (!StringUtils.hasLength(dto.getEndDate())) {
            return ApiResult.error("租赁结束时间不能为空");
        }
        if(StringUtils.hasLength(dto.getEndHour()) && dto.getEndHour().equals("24:00:00")){
            dto.setEndHour("23:59:59");
        }
        return ApiResult.success(parkSpaceService.calculatePrice(dto));
    }

    /**
     * 租赁
     *
     * @param dto 页面对象
     * @return 页面对象
     */
    @PostMapping(value = "/lease")
    public PayParamDTO lease(@Validated({DefaultGroup.class}) @RequestBody ParkSpaceTenantDTO dto) {
        RLock lock = redissonClient.getLock(dto.getSid());
        try {
            try {
                boolean res = lock.tryLock(30, 10, TimeUnit.MINUTES);
                if (res) {
                    return parkSpaceHolderService.lease(dto);
                } else {
                    throw new ApiException(ApiResult.error());
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error(UserStrokeHolderService.REDIS_LOCKED_ERR, e);
                throw new ApiException(ApiResult.error());
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * 停车码
     *
     * @return 页面对象
     */
    @GetMapping(value = "/parkCode")
    public ApiResultWrapper<Object> parkCode() {
        return ApiResult.success(parkSpaceHolderService.parkCode());
    }

    /**
     * 订单列表
     *
     * @param dto 查询参数以及页数和每页显示条数
     * @return 列表信息
     */
    @GetMapping(value = "/orderPage")
    public IPage<OwnParkSpaceTenantDTO> orderPage(OwnParkSpaceTenantDTO dto) {
        return parkSpaceTenantService.carOwnOrderPage(PageUtil.buildPage(dto));
    }

    /**
     * 订单详情
     *
     * @param id 主键
     * @return 记录
     */
    @GetMapping(value = "/getOrderById")
    public OwnParkSpaceTenantDTO getOrderById(@Validated @NotBlank(message = "ID不能为空") String id) {
        return parkSpaceTenantService.carOwnOrderById(id);
    }

    /**
     * 更新失败的支付状态
     */
    @PostMapping(value = "/updatePayErrState")
    public ApiResultWrapper<Object> updatePayErrState(@Validated @RequestBody Map<String, String> param) {
        String id = param.get("id");
        if (!StringUtils.hasLength(id)) {
            return ApiResult.error("id不能为空");
        }
        parkSpaceHolderService.updatePayState(id);
        return ApiResult.success("更新成功");
    }

    /**
     * 退款
     *
     * @param dto 页面对象
     * @return 页面对象
     */
    @PostMapping(value = "/refund")
    public ApiResultWrapper<Object> refund(@Validated @RequestBody ParkSpaceTenantDTO dto) {
        if (!StringUtils.hasLength(dto.getId())) {
            throw new ApiException("id不能为空");
        }
        RLock lock = redissonClient.getLock(dto.getId());
        try {
            try {
                boolean res = lock.tryLock(30, 10, TimeUnit.SECONDS);
                if (res) {
                    parkSpaceHolderService.refund(dto);
                    return ApiResult.success("退款成功");
                } else {
                    throw new ApiException(ApiResult.error());
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error(UserStrokeHolderService.REDIS_LOCKED_ERR, e);
                throw new ApiException(ApiResult.error());
            }
        } finally {
            lock.unlock();
        }
    }
}